package com.qwert.shortlink.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qwert.shortlink.admin.common.biz.user.UserContext;
import com.qwert.shortlink.admin.common.convention.exception.ClientException;
import com.qwert.shortlink.admin.common.convention.result.Result;
import com.qwert.shortlink.admin.common.enums.GroupErrorCode;
import com.qwert.shortlink.admin.dao.entity.Group;
import com.qwert.shortlink.admin.dao.mapper.GroupMapper;
import com.qwert.shortlink.admin.dto.req.group.ShortLinkGroupSaveReqDTO;
import com.qwert.shortlink.admin.dto.req.group.ShortLinkGroupSortReqDTO;
import com.qwert.shortlink.admin.dto.req.group.ShortLinkGroupUpdateReqDTO;
import com.qwert.shortlink.admin.dto.resp.group.ShortLinkGroupRespDTO;
import com.qwert.shortlink.admin.remote.dto.ShortLinkRemoteService;
import com.qwert.shortlink.admin.remote.dto.resp.shortlink.ShortLinkCountRespDTO;
import com.qwert.shortlink.admin.service.IGroupService;
import com.qwert.shortlink.admin.toolkit.RandomGenerator;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 短链接分组实现层
 * @author qwert
 * @version 1.0.0
 * @create 2024/6/26 15:09
 **/
@Service
public class GroupServiceImpl extends ServiceImpl<GroupMapper, Group> implements IGroupService {
    public final static int DEFAULT_SORT_ORDER = 0;
    public final static int EXIST_FLAG = 0;
    public final static int NOT_EXIST_FLAG = 1;

    ShortLinkRemoteService shortLinkRemoteService = new ShortLinkRemoteService() {
    };
    @Override
    public Integer saveGroup(ShortLinkGroupSaveReqDTO shortLinkGroupSaveReqDTO) {
        return this.saveGroup(UserContext.getUsername(), shortLinkGroupSaveReqDTO.getName());
    }

    @Override
    public Integer saveGroup(String username, String groupName) {
        String gid = this.getUniqueGroupId();
        Group group = Group.builder()
                .gid(gid)
                .name(groupName)
                .username(username)
                .sortOrder(DEFAULT_SORT_ORDER)
                .build();
        return baseMapper.insert(group);
    }

    @Override
    public List<ShortLinkGroupRespDTO> listGroup() {
        // 查询当前登录用户的全部分组
        LambdaQueryWrapper<Group> wrapper = Wrappers.lambdaQuery(Group.class)
                .eq(Group::getDelFlag, EXIST_FLAG)
                .eq(Group::getUsername, UserContext.getUsername())
                .orderByDesc(Group::getSortOrder, Group::getUpdateTime);
        List<Group> groups = baseMapper.selectList(wrapper);
        // 短链接组的链接数量（从短链接管理项目中获取）
        Result<List<ShortLinkCountRespDTO>> listResult =
                shortLinkRemoteService.listGroupShortLinkCount(groups.stream().map(Group::getGid).toList());
        // 将短链接分组的集合更新对应的短链接数量
        List<ShortLinkGroupRespDTO> shortLinkGroupRespDTOList = BeanUtil.copyToList(groups, ShortLinkGroupRespDTO.class);
        shortLinkGroupRespDTOList.forEach(each -> {
            // 获取首次与each.gid匹配的， 短链组的item.gid，首次出现的数据
            Optional<ShortLinkCountRespDTO> first = listResult.getData().stream()
                    .filter(item -> Objects.equals(item.getGid(), each.getGid()))
                    .findFirst();
            // 将对应的首次出现的数据更新到对应的分组集合中
            first.ifPresent(item -> each.setShortLinkCount(first.get().getShortLinkCount()));
        });
        return shortLinkGroupRespDTOList;
    }

    @Override
    public Integer updateGroup(ShortLinkGroupUpdateReqDTO shortLinkGroupUpdateReqDTO) {
        // 设置更新并更新到数据库
        LambdaUpdateWrapper<Group> wrapper = Wrappers.lambdaUpdate(Group.class)
                .eq(Group::getGid, shortLinkGroupUpdateReqDTO.getGid())
                .eq(Group::getUsername, UserContext.getUsername())
                .eq(Group::getDelFlag, EXIST_FLAG);

        // 组装数据
        Group group = new Group();
        group.setName(shortLinkGroupUpdateReqDTO.getName());
        group.setSortOrder(shortLinkGroupUpdateReqDTO.getSortOrder());

        // 更新数据库
        int updated = baseMapper.update(group, wrapper);
        if(updated < 1) {
            throw new ClientException(GroupErrorCode.GROUP_UPDATE_ERROR);
        }
        return updated;
    }

    @Override
    public Integer deleteGroup(String gid) {
        LambdaUpdateWrapper<Group> wrapper = Wrappers.lambdaUpdate(Group.class)
                .eq(Group::getGid, gid)
                .eq(Group::getUsername, UserContext.getUsername())
                .eq(Group::getDelFlag, EXIST_FLAG);
        Group group = new Group();
        group.setDelFlag(NOT_EXIST_FLAG);
        int updated = baseMapper.update(group, wrapper);
        if(updated < 1) {
            throw new ClientException(GroupErrorCode.GROUP_UPDATE_ERROR);
        }
        return updated;
    }

    @Override
    public Boolean sortGroup(List<ShortLinkGroupSortReqDTO> linkGroupSortReqDTOList) {
//        int updated = 0;
        linkGroupSortReqDTOList.forEach(groupSortDTO -> {
            Group group = Group.builder()
                    .gid(groupSortDTO.getGid())
                    .sortOrder(groupSortDTO.getSortOrder())
                    .build();
            LambdaUpdateWrapper<Group> updateWrapper = Wrappers.lambdaUpdate(Group.class)
                    .eq(Group::getUsername, UserContext.getUsername())
                    .eq(Group::getGid, groupSortDTO.getGid())
                    .eq(Group::getDelFlag, EXIST_FLAG);
            baseMapper.update(group, updateWrapper);
//            updated +=
        });
//        if(updated <linkGroupSortReqDTOList.size()){
//            return false;
//        }
        return true;
    }

    public String getUniqueGroupId() {
        // gid判重，根据用户名来查询自己是否有重复gid
        String gid = RandomGenerator.generateRandom();
        // 查询数据库是否存在groupId
        Group group = baseMapper.selectOne(Wrappers.lambdaQuery(Group.class).eq(Group::getGid, gid));
        if(group != null) {
            this.getUniqueGroupId();
        }
        return gid;
    }
}
